package p2pcdnsim.xml;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


import org.jdom.Element;

import p2pcdnsim.cdn.CDN;
import p2pcdnsim.cdn.CDNBuilder;
import p2pcdnsim.cdn.CachingStrategy;
import p2pcdnsim.cdn.OriginServer;
import p2pcdnsim.cdn.PlacementStrategy;
import p2pcdnsim.cdn.RequestRedirector;
import p2pcdnsim.cdn.Surrogate;
import p2pcdnsim.cdn.VideoContent;
import p2pcdnsim.cdn.VoDOriginServer;
import p2pcdnsim.cdn.VoDSurrogate;
import p2pcdnsim.exception.CacheClassInstantiationException;
import p2pcdnsim.exception.ClientDoesNotExistException;
import p2pcdnsim.exception.NodeUnexistentException;
import p2pcdnsim.exception.SurrogateAlreadyInsertedException;
import p2pcdnsim.network.NetworkTopology;


import desmoj.core.simulator.Model;
import desmoj.core.simulator.SimTime;


public class XMLVoDCDNBuilder extends CDNBuilder {

	private XMLHandler clientPlacementXMLHandler;
	private XMLHandler videoObjectsXMLHandler;
	private XMLHandler requestsXMLHandler;
	private XMLHandler cacheXMLHandler;
	
	private NetworkTopology topology;
	private PlacementStrategy placementStrategy;
	
	
	public XMLVoDCDNBuilder(
			XMLHandler cacheXMLHandler,
			XMLHandler clientPlacementXMLHandler,
			XMLHandler videoObjectsXMLHandler,
			XMLHandler requestsXMLHandler,
			NetworkTopology topology,
			PlacementStrategy placementStrategy) {
		this.cacheXMLHandler = cacheXMLHandler;
		this.clientPlacementXMLHandler = clientPlacementXMLHandler;
		this.videoObjectsXMLHandler = videoObjectsXMLHandler;
		this.requestsXMLHandler = requestsXMLHandler;
		this.topology = topology;
		this.placementStrategy = placementStrategy;
	}
	
	@Override
	public void createNewCDN(Model owner) {
		this.cdn = new CDN(owner,topology);
	}

	@Override
	public void defineClientPlacement() throws NodeUnexistentException {
		Iterator<Element> i = clientPlacementXMLHandler.iterator();
		
		while (i.hasNext()) {
			Element linksTemp = i.next();
			int   router  = Integer.parseInt(linksTemp.getChild("Router").getText());
			String clientID = linksTemp.getChild("Client").getText();
			
			this.cdn.placeClient(Long.parseLong(clientID), router);
		}
	}

	@Override
	public void createAndPlaceOriginServer() throws NodeUnexistentException {
		OriginServer os = new VoDOriginServer(cdn,"OriginServer");
		
		Iterator<Element> i = videoObjectsXMLHandler.iterator();
		
		while (i.hasNext()) {
			Element linksTemp = i.next();
			int id    = Integer.parseInt(linksTemp.getChild("Id").getText());
			long size  = Long.parseLong(linksTemp.getChild("Size").getText());
			int bitrate    = Integer.parseInt(linksTemp.getChild("BitRate").getText());
			
			//System.out.println(id+" "+size+" "+bitrate);
			VideoContent content = new VideoContent(id,size,bitrate);
			os.addContent(content);
		}
		
		//Place Origin Server into CDN infrastructure
		cdn.placeOriginServer(os,topology.getNode(4));
	}

	@Override
	public void createAndPlaceRequestRedirector() throws NodeUnexistentException {
		RequestRedirector redirector = new RequestRedirector(cdn,"RequestRedirector");
		cdn.placeRequestRedirector(redirector,topology.getNode(1));
	}

	
	@Override
	public void createAndPlaceSurrogates() throws CacheClassInstantiationException, SurrogateAlreadyInsertedException {
		List<Surrogate> surrogates = new ArrayList<Surrogate>();
		
		Iterator<Element> i = cacheXMLHandler.iterator();
		
		while (i.hasNext()) {
			Element element = i.next();
			long cacheSize = Long.parseLong(element.getChild("CacheSize").getText());
			long SurrogateId  = Long.parseLong(element.getChild("SurrogateId").getText());
			String cachePolicy  = element.getChild("CachePolicy").getText();
			
			CachingStrategy<VideoContent> cache = createCache(cachePolicy);
			cache.setCacheSize(cacheSize);
			Surrogate surrogate = new VoDSurrogate(cdn.getModel(), "Surrogate"+SurrogateId, cdn, cache);
			surrogates.add(surrogate);

			if(element.getChild("ObjectsStored")!=null) {
				@SuppressWarnings("unchecked")
				Iterator<Element> objects = element.getChild("ObjectsStored").getChildren().iterator();
				while(objects.hasNext()) {
					Element object = objects.next();
					long objectId = Long.parseLong(object.getText());
					cache.insertObject((VideoContent)cdn.getOriginServer().getContent(objectId), new SimTime(0.0));
				}
			}
		}

		
		placementStrategy.placeSurrogates(surrogates,cdn);
	}

	@Override
	public void insertClientRequests() throws ClientDoesNotExistException {
		Iterator<Element> i = requestsXMLHandler.iterator();
		
		while (i.hasNext()) {
			Element linksTemp = i.next();
			double timeStamp = Double.parseDouble(linksTemp.getChild("Timestamp").getText());
			long   clientID  = Long.parseLong(linksTemp.getChild("Client").getText());
			int   objectID  = Integer.parseInt(linksTemp.getChild("VideoObject").getText());
			
			this.cdn.addClientRequest(timeStamp,clientID,objectID);

		}		
	}

	@SuppressWarnings("unchecked")
	private CachingStrategy<VideoContent> createCache(String cacheClass) throws CacheClassInstantiationException {
		CachingStrategy<VideoContent> cache;
		try {
			Class type = Class.forName(cacheClass);
			cache = (CachingStrategy<VideoContent>) type.newInstance();
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new CacheClassInstantiationException(e);
		}
		return cache;
	}
	
}
